import { Vector2 } from './Vector2';
import { BaseCollider } from './BaseCollider';
import {
    Collider,
    ColliderType,
    CircleColliderOptions,
    CollisionResult
} from './types';

/**
 * 圆形碰撞体类
 */
export class CircleCollider extends BaseCollider {
    public readonly radius: number;
    
    constructor(options: CircleColliderOptions) {
        super(options);
        
        this.radius = options.radius;
        this.updateBounds();
    }
    
    /**
     * 检查是否与另一个碰撞体相交
     */
    public intersects(other: Collider): boolean {
        if (!this.canCollideWith(other)) {
            return false;
        }
        
        switch (other.type) {
            case ColliderType.RECTANGLE:
                return this.intersectsRectangle(other);
            case ColliderType.CIRCLE:
                return this.intersectsCircle(other as CircleCollider);
            case ColliderType.POLYGON:
                return this.intersectsPolygon(other);
            default:
                return false;
        }
    }
    
    /**
     * 检查点是否在碰撞体内
     */
    public contains(point: Vector2): boolean {
        const local = this.worldToLocal(point);
        return local.length <= this.radius;
    }
    
    /**
     * 获取碰撞体中心点
     */
    public getCenter(): Vector2 {
        return this.position.clone().add(this.offset);
    }
    
    /**
     * 获取碰撞体面积
     */
    public getArea(): number {
        return Math.PI * this.radius * this.radius * this.scale.x * this.scale.y;
    }
    
    /**
     * 克隆碰撞体
     */
    public clone(): CircleCollider {
        return new CircleCollider({
            type: ColliderType.CIRCLE,
            radius: this.radius,
            isTrigger: this.isTrigger,
            tag: this.tag,
            layer: this.layer,
            offset: this.offset.clone(),
            rotation: this.rotation,
            scale: this.scale.clone(),
            enabled: this.enabled
        });
    }
    
    /**
     * 更新碰撞体边界
     */
    protected updateBounds(): void {
        const center = this.getCenter();
        const scaledRadius = this.radius * Math.max(this.scale.x, this.scale.y);
        
        this.bounds.min = center.clone().subtract(new Vector2(scaledRadius, scaledRadius));
        this.bounds.max = center.clone().add(new Vector2(scaledRadius, scaledRadius));
    }
    
    /**
     * 计算两个碰撞体之间的碰撞结果
     */
    protected calculateCollision(other: Collider): CollisionResult {
        switch (other.type) {
            case ColliderType.RECTANGLE:
                return this.calculateRectangleCollision(other);
            case ColliderType.CIRCLE:
                return this.calculateCircleCollision(other as CircleCollider);
            case ColliderType.POLYGON:
                return this.calculatePolygonCollision(other);
            default:
                return { collided: false };
        }
    }
    
    /**
     * 检查是否与矩形碰撞体相交
     */
    private intersectsRectangle(other: Collider): boolean {
        const result = this.calculateRectangleCollision(other);
        return result.collided;
    }
    
    /**
     * 检查是否与圆形碰撞体相交
     */
    private intersectsCircle(other: CircleCollider): boolean {
        const result = this.calculateCircleCollision(other);
        return result.collided;
    }
    
    /**
     * 检查是否与多边形碰撞体相交
     */
    private intersectsPolygon(other: Collider): boolean {
        const result = this.calculatePolygonCollision(other);
        return result.collided;
    }
    
    /**
     * 计算与矩形碰撞体的碰撞结果
     */
    private calculateRectangleCollision(other: Collider): CollisionResult {
        // 获取圆形的中心点和矩形的中心点
        const circleCenter = this.getCenter();
        const rectCenter = other.getCenter();
        
        // 将圆形中心点转换到矩形的局部坐标系
        const localCircle = (other as any).worldToLocal(circleCenter);
        
        // 找到矩形上距离圆形中心最近的点
        const closest = new Vector2(
            Math.max(-(other as any).halfWidth, Math.min((other as any).halfWidth, localCircle.x)),
            Math.max(-(other as any).halfHeight, Math.min((other as any).halfHeight, localCircle.y))
        );
        
        // 计算圆形中心到最近点的距离
        const distance = closest.distance(localCircle);
        const scaledRadius = this.radius * this.scale.x;
        
        // 如果没有重叠，则没有碰撞
        if (distance > scaledRadius) {
            return { collided: false };
        }
        
        // 计算碰撞法线和穿透深度
        const normal = (other as any).localToWorld(closest).subtract(circleCenter).normalized;
        const penetration = scaledRadius - distance;
        
        // 计算碰撞点
        const contactPoint = circleCenter.clone().add(normal.clone().multiply(scaledRadius));
        
        return {
            collided: true,
            contactPoint,
            normal,
            penetration
        };
    }
    
    /**
     * 计算与圆形碰撞体的碰撞结果
     */
    private calculateCircleCollision(other: CircleCollider): CollisionResult {
        // 获取两个圆形的中心点
        const centerA = this.getCenter();
        const centerB = other.getCenter();
        
        // 计算两个圆心之间的距离
        const distance = centerA.distance(centerB);
        const radiusA = this.radius * this.scale.x;
        const radiusB = other.radius * other.scale.x;
        const minDistance = radiusA + radiusB;
        
        // 如果没有重叠，则没有碰撞
        if (distance > minDistance) {
            return { collided: false };
        }
        
        // 计算碰撞法线和穿透深度
        const normal = centerB.subtract(centerA).normalized;
        const penetration = minDistance - distance;
        
        // 计算碰撞点
        const contactPoint = centerA.clone().add(normal.clone().multiply(radiusA));
        
        return {
            collided: true,
            contactPoint,
            normal,
            penetration
        };
    }
    
    /**
     * 计算与多边形碰撞体的碰撞结果
     */
    private calculatePolygonCollision(other: Collider): CollisionResult {
        // 获取多边形的顶点
        const vertices = (other as any).vertices.map((v: Vector2) => {
            const worldPos = new Vector2();
            // 假设多边形碰撞体有类似的方法
            if (typeof (other as any).localToWorld === 'function') {
                return (other as any).localToWorld(v);
            }
            return worldPos;
        });
        
        // 获取圆形的中心点和半径
        const circleCenter = this.getCenter();
        const scaledRadius = this.radius * this.scale.x;
        
        // 检查多边形的顶点是否与圆形相交
        for (const vertex of vertices) {
            const distance = circleCenter.distance(vertex);
            if (distance <= scaledRadius) {
                return {
                    collided: true,
                    contactPoint: vertex.clone(),
                    normal: vertex.subtract(circleCenter).normalized,
                    penetration: scaledRadius - distance
                };
            }
        }
        
        // 检查多边形的边是否与圆形相交
        for (let i = 0; i < vertices.length; i++) {
            const start = vertices[i];
            const end = vertices[(i + 1) % vertices.length];
            const edge = end.subtract(start);
            const edgeLength = edge.length;
            const edgeNormal = new Vector2(-edge.y, edge.x).normalized;
            
            // 计算圆心到边的距离
            const toCircle = circleCenter.subtract(start);
            const projection = toCircle.dot(edge) / edgeLength;
            const closest = start.clone().add(edge.clone().multiply(Math.max(0, Math.min(1, projection / edgeLength))));
            const distance = circleCenter.distance(closest);
            
            if (distance <= scaledRadius) {
                return {
                    collided: true,
                    contactPoint: closest.clone(),
                    normal: edgeNormal,
                    penetration: scaledRadius - distance
                };
            }
        }
        
        // 检查圆形是否完全在多边形内部
        if ((other as any).contains(circleCenter)) {
            // 找到多边形上距离圆心最近的点
            let minDistance = Infinity;
            let closestPoint = new Vector2();
            
            for (const vertex of vertices) {
                const distance = circleCenter.distance(vertex);
                if (distance < minDistance) {
                    minDistance = distance;
                    closestPoint = vertex.clone();
                }
            }
            
            return {
                collided: true,
                contactPoint: closestPoint,
                normal: circleCenter.subtract(closestPoint).normalized,
                penetration: scaledRadius + minDistance
            };
        }
        
        return { collided: false };
    }
} 